import {
    _decorator,
    Collider,
    Component,
    ICollisionEvent,
    instantiate,
    Prefab,
    ParticleSystem,
    Node,
    Vec3,
    resources
} from 'cc';
import {MonsterViewModel} from "db://assets/Scripts/MVC/Monster/MonsterViewModel";
import {MonsterUiState} from "db://assets/Scripts/MVC/Monster/MonsterUiState";
import {MonsterType} from "db://assets/Scripts/MVC/Monster/MonsterType";
import {ModelPath} from "db://assets/Scripts/Common/ModelPath";
import {CollisionGroup} from "db://assets/Scripts/Common/CollisionGroup";
import {EventManager} from "db://assets/Scripts/Common/EventManager";
import {EventType} from "db://assets/Scripts/Common/EventType";
import {AudioManager} from "db://assets/Scripts/Common/AudioManager";
import {AudioPath} from "db://assets/Scripts/Common/AudioPath";
import {PoolManager} from "db://assets/Scripts/framework/PoolManager";
import {EffectPath} from "db://assets/Scripts/Common/EffectPath";

const {ccclass, property} = _decorator;

/**
 * 敌人控制器
 */
@ccclass('MonsterController')
export class MonsterController extends Component {
    /**
     * 业务逻辑
     */
    public viewModel: MonsterViewModel = new MonsterViewModel();
    /**
     * 界面状态
     */
    public uiState: MonsterUiState = this.viewModel.uiState;

    onLoad() {
        // 初始化模型
        this.initModel();
    }

    onEnable() {
        // 添加碰撞检测
        this.getComponent(Collider).on('onCollisionEnter', this.onCollisionEnter, this);
    }

    onDisable() {
        // 移除碰撞检测
        this.getComponent(Collider).off('onCollisionEnter', this.onCollisionEnter, this);
    }

    start() {

    }

    update(deltaTime: number) {
        // 检测飞机是否处于保护期
        this.checkProtective();
        // 移动
        this.move(deltaTime);
        // 子弹
        this.createBullet(deltaTime);
        // 销毁
        this.remove();
    }

    /**
     * 初始化模型
     */
    private initModel() {
        // 加载敌机子弹
        resources.load(ModelPath.monsterBullet, Prefab, (err, data) => {
            if (err) {
                console.error("敌机子弹模型资源加载失败！");
                return;
            }

            this.uiState.monsterBulletPrefab = data;
        });
        // 加载爆炸特效
        resources.load(EffectPath.explodeSmall, Prefab, (err, data) => {
            if (err) {
                console.log("爆炸特效加载失败！");
                return;
            }

            this.uiState.enemyDiedEffectPrefab = data;
        });
    }

    /**
     * 检测飞机是否无敌
     * 暂定：在飞机未飞入画面前都是保护期，不被攻击
     */
    private checkProtective() {
        if (this.node.position.z > -8) {
            this.uiState.protective = false;
        }
    }

    /**
     * 移动
     *
     * @param deltaTime 帧间隔
     */
    private move(deltaTime: number) {
        // 获取位置
        const position = this.node.position;
        // 设置位置
        this.node.setPosition(position.x, position.y, position.z + this.uiState.speed * deltaTime);
    }

    /**
     * 销毁
     */
    private remove() {
        // 获取位置
        let position = this.node.position;
        // 当超过最大范围时
        if (position.z > this.uiState.outRange) {
            // 销毁敌人
            // this.node.destroy();
            this.recycle();
        }
    }

    /**
     * 子弹
     */
    private createBullet(deltaTime: number) {
        // 非超级战机
        if (this.uiState.type !== MonsterType.SUPER) {
            return;
        }

        // 保护期的
        if (this.uiState.protective) {
            return;
        }

        // 叠加攻击间隔
        this.uiState.currentAttackInterval += deltaTime;
        // 攻击
        if (this.uiState.currentAttackInterval >= this.uiState.attackInterval) {
            // 实例化子弹
            const bulletNode = PoolManager.getInstance().getNode(this.uiState.monsterBulletPrefab, this.node.parent);
            // 设置敌机子弹位置
            let position = this.node.position;
            bulletNode.setPosition(position.x, position.y, position.z + 1);
            // 重置发射周期
            this.uiState.currentAttackInterval = 0;
        }
    }

    /**
     * 碰撞检测
     *
     * @param event 碰撞事件
     */
    private onCollisionEnter(event: ICollisionEvent) {
        // 另一个碰撞器的分组
        const otherGroup = event.otherCollider.getGroup();

        // 当飞机不处于保护期且被玩家子弹击中时
        if (!this.uiState.protective && otherGroup === CollisionGroup.PLAYER_BULLET) {
            // 当敌人没有死亡时
            if (this.viewModel.isLive()) {
                // 生命值-1
                this.uiState.hp -= 1;

                // 当敌人死亡时
                if (!this.viewModel.isLive()) {
                    // 死亡动画
                    this.died();
                    // 分数+1
                    EventManager.emit(EventType.UPDATE_SCORE, 1);
                }
            }
        }

        // 与玩家飞机发生碰撞时
        if (!this.uiState.protective && otherGroup === CollisionGroup.PLAYER_PLANE) {
            // 死亡动画
            this.died();
        }
    }

    /**
     * 敌人死亡
     */
    private died() {
        // 播放死亡声音
        AudioManager.getInstance().playSound(AudioPath.enemyDiedSound);
        // 播放死亡动画
        this.playDiedEffect(this.node.parent, this.node.position);
        // 回收节点
        this.recycle();
    }

    /**
     * 回收节点
     */
    private recycle() {
        // 回收节点
        PoolManager.getInstance().putNode(this.node);
        // 重置ViewModel
        this.viewModel.reset();
    }

    /**
     * 播放死亡动画
     *
     * @param parent 动画节点的父节点
     * @param position 动画节点的位置
     */
    private playDiedEffect(parent: Node, position: Vec3) {
        // 爆炸节点
        const tailFlameNode = PoolManager.getInstance().getNode(this.uiState.enemyDiedEffectPrefab, parent);
        // 设置位置
        tailFlameNode.setPosition(position);
        // 回收特效节点
        const pss: ParticleSystem[] = tailFlameNode.getComponentsInChildren(ParticleSystem);
        const interval = setInterval(() => {
            // 查找正在播放特效的节点
            const index = pss.findIndex(ps => ps.isPlaying);
            // 当所有特效都播放完毕时
            if (index === -1) {
                // 回收特效节点
                PoolManager.getInstance().putNode(tailFlameNode);
                // 取消定时器
                clearInterval(interval);
            }
        }, 1000);
    }
}